using System;
using System.IO;
using System.Threading.Tasks;
using ControlCenter.Model;
using ControlCenter.Operation;
using MingYuanYun.Context.Abstractions;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using System.Linq;
using ControlCenter.ApplicationService.Services.Utility;
using ControlCenter.Model.BizEntities;
using ControlCenter.Model.WebApiDto;
using MingYuanYun.Exception;
using MingYuanYun.Primitives;
using MingYuanYun.Utility;

namespace ControlCenter.ApplicationService
{
    /// <summary>
    /// 包管理
    /// </summary>
    public class PackageManagementService : ApplicationServiceBase, IPackageManagementService
    {
        private readonly string _packageSavePath;
        private readonly IPackageManagementOperation _packageManagementOperation;
        private readonly IParamService _iParamService;
        private readonly IRobotService _iRobotService;

        /// <summary>
        /// 服务初始化
        /// </summary>
        /// <param name="context"></param>
        public PackageManagementService(IServiceContext context) : base(context)
        {
            _packageSavePath = this.GetConfig<string>("PackageSavePath");
            _packageManagementOperation = this.GetService<IPackageManagementOperation>();
            _iParamService = this.GetService<IParamService>();
            _iRobotService = this.GetService<IRobotService>();
        }

        #region  -- 包文件操作 -------------------------------------------------------------------------------------------------------
        /// <summary>
        /// 查询指定包信息
        /// </summary>
        /// <param name="packageId"></param>
        /// <returns></returns>
        public async Task<(byte[] fileStream, ProjectPackageInfo packageInfoDto)> ReadPackageFile(Guid packageId)
        {
            try
            {
                var packageInfo = await _packageManagementOperation.FindPackageInfo(packageId);
                string filePath = AppDomain.CurrentDomain.BaseDirectory + packageInfo.DownloadUrl;
                if (!File.Exists(filePath))
                {
                    throw new Exception("服务器本地不存在包文件");
                }

                var fileByte = File.ReadAllBytes(filePath);
                return (fileByte, packageInfo);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        /// <summary>
        /// 保存文件到本地
        /// </summary>
        /// <param name="packageInfoDto"></param>
        /// <param name="package"></param>
        /// <returns></returns>
        public async Task<bool> SavePackages(PackageInfoDto packageInfoDto, IFormFile package)
        {
            if (!string.Equals(".nupkg", Path.GetExtension(package.FileName), StringComparison.CurrentCultureIgnoreCase))
            {
                throw new Exception("不支持此文件格式，请上传.nupkg文件。");
            }

            var isExist = await _packageManagementOperation.IsExist(packageInfoDto.ProjectName, packageInfoDto.Version);

            if (isExist)
            {
                throw new Exception("改Package此版本已存在。");
            }
            if (!Directory.Exists(_packageSavePath))
            {
                Directory.CreateDirectory(_packageSavePath);
            }

            string filePath = Path.Combine(_packageSavePath, $"{packageInfoDto.ProjectName}.{packageInfoDto.Version}.nupkg");
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            using (var fileStream = new FileStream(filePath, FileMode.Create))
            {
                await package.CopyToAsync(fileStream);
            }

            await _packageManagementOperation.SavePackageInfo(packageInfoDto.ToProjectPackageInfo());

            return true;
        }
        #endregion

        #region -- 机器人的包管理 -------------------------------------------------------------------------------------------------------
        /// <summary>
        /// 获取所有机器人的应用摘要信息列表
        /// </summary>
        /// <returns></returns>
        public async Task<IEnumerable<RobotPackageShortInfo>> QueryRobotPackageShortInfo()
        {
            return await _packageManagementOperation.QueryRobotPackageShortInfo();
        }

        /// <summary>
        /// 查询机器人待执行的任务包
        /// </summary>
        /// <param name="robotId"></param>
        /// <returns></returns>
        public async Task<IEnumerable<RobotPackageInfo>> QueryRobotPackageInfo(Guid robotId)
        {
            return await _packageManagementOperation.QueryPackage(robotId);
        }

        /// <summary>
        /// 读取机器人的包信息列表，供编辑机器人包使用
        /// </summary>
        /// <param name="robotId"></param>
        /// <returns></returns>
        public async Task<IEnumerable<WaitExecutionPackageDto>> QueryRobotWaitExectionPackage(Guid robotId)
        {
            var packageDto = await _packageManagementOperation.QueryWaitExectionPackage(robotId);
            var robot = await _iRobotService.GetRobot(robotId);
            if (robot.Status == RobotStatus.Disabled)
            {
                packageDto.ForEach(p=>p.PackageStatus = PackageStatus.Stop);
            }
            return packageDto;
        }

        /// <summary>
        /// 读取机器人的包信息列表，供编辑机器人包使用
        /// </summary>
        /// <param name="robotId"></param>
        /// <returns></returns>
        public async Task<IEnumerable<SaveRobotPackageInfo>> QuerySaveRobotPackageInfo(Guid robotId)
        {
            return await _packageManagementOperation.QuerySaveRobotPackageInfo(robotId);
        }

        /// <summary>
        /// 保存机器人的包及设定数据
        /// </summary>
        /// <param name="saveDto"></param>
        /// <returns></returns>
        public async Task<bool> UpdateRobotPackageInfo(SaveRobotInfoDto saveDto)
        {
            return await _packageManagementOperation.UpdateRobotPackageInfo(saveDto);
        }

        /// <summary>
        /// 更新机器人的包状态（启用/停用）
        /// </summary>
        /// <param name="rpId"></param>
        /// <param name="packageStatus"></param>
        /// <returns></returns>
        public async Task UpdateRobotPackagePackageStatus(Guid rpId, int packageStatus)
        {
            await _packageManagementOperation.UpdateRobotPackagePackageStatus(rpId, packageStatus);
        }

        /// <summary>
        /// 删除机器人的包
        /// </summary>
        /// <param name="rpId"></param>
        /// <returns></returns>
        public async Task DeleteRobotPackage(Guid rpId)
        {
            await _packageManagementOperation.DeleteRobotPackage(rpId);
        }
        #endregion


        #region -- 包管理 -------------------------------------------------------------------------------------------------------
        /// <summary>
        /// 查询包，返回包信息列表
        /// </summary>
        /// <param name="paramDto"></param>
        /// <returns></returns>
        public async Task<PagedData<ProjectPackageInfo>> QueryPackageInfo(PackageQueryDto paramDto)
        {
            ValidateQueryPackageInfo(paramDto);
            return await _packageManagementOperation.QueryPackageInfo(paramDto);
        }
        
        // QueryPackageInfo参数验证
        private void ValidateQueryPackageInfo(PackageQueryDto paramDto)
        {
            ExceptionAssert.IsNull(paramDto, nameof(paramDto));
            ExceptionAssert.IsTrue(paramDto.PageIndex <= 0, $"{nameof(paramDto.PageIndex)} 不能<=0");
            ExceptionAssert.IsTrue(paramDto.PageSize > 10000, $"{nameof(paramDto.PageSize)} 不能>10000");
        }

        /// <summary>
        /// 获取单个包信息
        /// </summary>
        /// <param name="packageId"></param>
        /// <returns></returns>
        public async Task<ProjectPackageInfo> FindPackageInfo(Guid packageId)
        {
            ExceptionAssert.IsTrue(packageId == Guid.Empty, $"{nameof(packageId)} 不能为空");
            return await _packageManagementOperation.FindPackageInfo(packageId);
        }

        /// <summary>
        /// 更新包信息（不存在时新增）
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        public async Task<Tuple<bool, string>> SavePackageInfo(ProjectPackageInfo param)
        {
            //校验请求参数
            ValidateSavePackageInfo(param);

            //将文件从临时目录移动到正式目录
            string saveFilename = SaveNupkg(param);
            var nupkgInfo = await NupkgFile.ReadNuspec(saveFilename);

            if (param.PackageId != Guid.Empty)
            {
                return await UpdatePackage(param, nupkgInfo);
            }
            else
            {
                return await AddPackage(param, nupkgInfo);
            }
        }

        private async Task<Tuple<bool, string>> AddPackage(ProjectPackageInfo param, NuspecInfo nupkgInfo)
        {
            ProjectPackageInfo oldPackage = await _packageManagementOperation.FindPackageInfo(param.ProjectName);
            if (oldPackage != null)
            {
                param.PackageId = oldPackage.PackageId;
                return await UpdatePackage(param, nupkgInfo, true);
            }
            else
            {
                //应用不重复，则新增
                param.PackageId = Guid.NewGuid();
                List<PackageConfigItem> pkgConfigItems = GetNewPackageConfigItems(param.PackageId, null, nupkgInfo);

                var addRet = await _packageManagementOperation.InsertPackageInfo(param, pkgConfigItems);
                return new Tuple<bool, string>(addRet, addRet ? "成功" : "数据库操作失败");
            }
        }

        private async Task<Tuple<bool, string>> UpdatePackage(ProjectPackageInfo param, NuspecInfo nupkgInfo, bool isRequestAdd = false)
        {
            ProjectPackageInfo oldPackage = await _packageManagementOperation.FindPackageInfo(param.PackageId);
            if (oldPackage == null)
            {
                throw new BusinessException($"应用不存在！Guid={param.PackageId}");
            }

            if (oldPackage.ProjectName != param.ProjectName)
            {
                throw new BusinessException("只能对相同的应用进行更新！");
            }

            //版本号检查
            Version oldVersion = new Version(oldPackage.Version);
            Version newVersion = new Version(param.Version);
            if (newVersion > oldVersion)
            {
                //版本号高于已有应用，则提示更新。
                oldPackage.ProjectName = param.ProjectName;
                oldPackage.DownloadUrl = param.DownloadUrl;
                oldPackage.UpdateTime = param.UpdateTime;
                oldPackage.Version = param.Version;

                //读取新增的环境变量
                var oldPackageConfigItems = await _packageManagementOperation.QueryPackageConfig(param.PackageId);
                List<PackageConfigItem> pkgConfigItems = GetNewPackageConfigItems(param.PackageId, oldPackageConfigItems.ToList(), nupkgInfo);

                //保存更新
                var updateRet = await _packageManagementOperation.UpdatePackageInfo(param, pkgConfigItems);
                return new Tuple<bool, string>(updateRet, updateRet ? "成功" : "数据库操作失败");
            }
            else
            {
                return new Tuple<bool, string>(false, isRequestAdd ? "已存在应用及最新版本，不需要更新！" : "版本号不能低于已有版本！");
            }
        }

        private string SaveNupkg(ProjectPackageInfo param)
        {
            string saveFilename = "";
            if (param.DownloadUrl.StartsWith("/upload/temp/")) //TODO:处理硬编码
            {
                var savePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "upload", "nupkg");
                if (!Directory.Exists(savePath))
                {
                    Directory.CreateDirectory(savePath);
                }

                var tempSaveFilename = AppDomain.CurrentDomain.BaseDirectory + param.DownloadUrl.Replace("/", @"\");
                param.DownloadUrl = param.DownloadUrl.Replace("/upload/temp/", "/upload/nupkg/");
                saveFilename = AppDomain.CurrentDomain.BaseDirectory + param.DownloadUrl.Replace("/", @"\");
                File.Copy(tempSaveFilename, saveFilename, true);

                return saveFilename;
            }
            else
            {
                return param.DownloadUrl;
            }
        }

        private List<PackageConfigItem> GetNewPackageConfigItems(Guid packageId, List<PackageConfigItem> oldItems,
            NuspecInfo nupkgInfo)
        {
            if (packageId == Guid.Empty)
            {
                throw new ArgumentNullException(nameof(packageId));
            }
            if (oldItems == null)
            {
                oldItems = new List<PackageConfigItem>();
            }
            if (nupkgInfo == null)
            {
                throw new ArgumentNullException(nameof(nupkgInfo));
            }

            List<PackageConfigItem> pkgConfigItems = new List<PackageConfigItem>();
            int seq = oldItems == null || oldItems.Count == 0 ? 1 : (oldItems.Max(p=>p.Sequence)+1);
            foreach (var nupkgInfoConfigItem in nupkgInfo.ConfigItems)
            {
                if (oldItems.FirstOrDefault(p => p.Name == nupkgInfoConfigItem.Name) == null)
                {
                    var pkgConfigItem = new PackageConfigItem
                    {
                        Sequence = seq++,
                        PackageId = packageId,
                        Name = nupkgInfoConfigItem.Name,
                        Type = nupkgInfoConfigItem.Type,
                        DefaultValue = nupkgInfoConfigItem.DefaultValue,
                        Value = nupkgInfoConfigItem.DefaultValue,
                        Remark = nupkgInfoConfigItem.Remark,
                        IsRequired = true,
                        IsSystem = true
                    };
                    pkgConfigItems.Add(pkgConfigItem);
                }
            }
            return pkgConfigItems;
        }

        // SavePackageInfo参数验证
        private void ValidateSavePackageInfo(ProjectPackageInfo param)
        {
            ExceptionAssert.IsNull(param, nameof(param));

            string errorMsg = "";
            if (string.IsNullOrEmpty(param.ProjectName))
            {
                errorMsg += $"{nameof(param.ProjectName)} 不能为空；";
            }
            if (string.IsNullOrEmpty(param.Version))
            {
                errorMsg += $"{nameof(param.Version)} 不能为空；";
            }
            if (string.IsNullOrEmpty(param.DownloadUrl))
            {
                errorMsg += $"{nameof(param.DownloadUrl)} 不能为空；";
            }
            if (!string.IsNullOrEmpty(errorMsg))
            {
                throw new BusinessException(errorMsg);
            }
        }

        /// <summary>
        /// 删除包，已被机器人使用的包不允许删除
        /// </summary>
        /// <param name="packageId"></param>
        /// <returns></returns>
        public async Task<Tuple<bool, string>> DeletePackageInfo(Guid packageId)
        {
            ExceptionAssert.IsTrue(packageId == Guid.Empty, $"{nameof(packageId)} 不能为空");
            return await _packageManagementOperation.DeletePackageInfo(packageId);
        }
        #endregion

        ///// <summary>
        ///// 更新包状态
        ///// </summary>
        ///// <param name="updatePackageStatusDto"></param>
        ///// <returns></returns>
        //public async Task<bool> UpdatePackageStatus(UpdatePackageStatusDto updatePackageStatusDto)
        //{
        //    return await _packageManagementOperation.UpdatePackageStatus(updatePackageStatusDto);
        //}

        #region -- 包参数配置 -------------------------------------------------------------------------------------------------------

        /// <summary>
        /// 查询指定应用包的参数配置
        /// </summary>
        /// <param name="packageId">应用包ID</param>
        /// <returns></returns>
        public async Task<List<PackageConfigItem>> QueryPackageConfig(Guid packageId)
        {
            ExceptionAssert.IsTrue(packageId == Guid.Empty, $"{nameof(packageId)} 不能为空");
            var queryRet = await _packageManagementOperation.QueryPackageConfig(packageId);
            return queryRet.ToList();
        }

        /// <summary>
        /// 更新应用包的参数配置
        /// </summary>
        /// <param name="packageConfigItems"></param>
        /// <returns></returns>
        public async Task<Tuple<bool, string>> UpdatePackageConfig(List<PackageConfigItem> packageConfigItems)
        {
            //参数校验
            ValidateUpdatePackageConfig(packageConfigItems);
            //重新编号
            int sequence = 1;
            packageConfigItems.ForEach(item=>item.Sequence = sequence++);
            var updateRet = await _packageManagementOperation.UpdatePackageConfig(packageConfigItems);
            return updateRet;
        }

        //UpdatePackageConfig 参数校验
        private void ValidateUpdatePackageConfig(List<PackageConfigItem> packageConfigItems)
        {
            ExceptionAssert.IsTrue(packageConfigItems == null || packageConfigItems.Count == 0, $"{nameof(packageConfigItems)} 不能为空");

            foreach (var item in packageConfigItems)
            {
                ExceptionAssert.IsNullOrEmpty(item.Value, $"{item.Name} 不能为空");
            }
        }
        #endregion
    }
}
